typedef float real;

#include <vector>
#define GLM_FORCE_SSE2 
//#define GLM_FORCE_INLINE 
#include <glm\glm.hpp>
#include "glm\gtc/type_ptr.hpp"

class Shader;

class FluidSolver
{
	static const int MAX_PARTICLES = 1024*80;

	// The particle structure holding all of the relevant information.
	struct particle 
	{ 
		glm::vec3 pos;
		glm::vec3 pos_old;
		glm::vec3 vel;
		glm::vec3 force; 
		real rho, rho_near, press, press_near, sigma, beta; 
		particle* succ;
		int id;
	};

private:
	int N;                     // Number of Particles in the simulation
	real spacing, k, k_near, rest_density, sigma, beta, SIM_W, bottom;
	real r, rsq, inv_r;
	// Our collection of particles
	int particlesCreated;

	// Mouse attractor
	glm::vec3 attractor;
	

	particle particles[MAX_PARTICLES];
	std::vector< glm::vec3 > verts;

	
	void update_grid();
	void calc_density();
	void calc_viscosity();
	void calc_pressure();
	void advance_particles_euler();
	void advance_particles_verlet();

private:
	unsigned int VertexVBOID;
	Shader *colorShader;

	void generateColorLUT();

	real G_factor;
	
public:
	void initParticles();
	double uploadTime;
	int attracting, repelling;
	bool do_viscosity_step;
	
	glm::vec3 G;

	int grid_width, grid_height, grid_depth;
	//typedef std::vector<std::vector<std::vector< particle* >>>> particle_3d_grid;
	particle** grid;
	FluidSolver();
	~FluidSolver();
	void render();
	void update();
	void activateAttractor( int x, int y );
	void deactivateAttractor();
	void addParticles( int x, int y );
	int getParticleCount() { return particlesCreated; }
	void activateRepelling( int mx, int my );
	void removeAllParticles() { particlesCreated = 0; }
	void reinstallShader();
};